home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / RevRdist Folder / RevRdist / RevRdist src / distfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-15  |  21.0 KB  |  940 lines  |  [TEXT/KAHL]

  1. /*
  2.  * distfile.c - routines for reading/writing the distribution control file
  3.  */
  4.  
  5. #include "RevRdist.h"
  6. #include "dispatch.h"
  7. #include "TransSkelProto.h"
  8. #include "TransDisplayProto.h"
  9.  
  10. /*
  11.  * iob - the structure used when reading the control file.
  12.  * we do the I/O ourselves rather than include all of the stdio library.
  13.  */
  14.  
  15. struct iob
  16. {
  17.     int            size;                /* the size of the buffer */
  18.     int            cnt;                /* number of bytes in the buffer */
  19.     int            idx;                /* index of next byte in buffer */
  20.     Integer        refNum;                /* file reference number */
  21.     Byte        buf[1];                /* I/O buffer */
  22. };
  23.  
  24. static    Str31    alias;                /* word for "alias" */
  25. static    Str31    icons;                /* word for "icon file" */
  26.  
  27.  
  28. static    OSErr getDActions (StringPtr, actions_t *);
  29. static    int getDField (StringPtr, int *, int, StringPtr);
  30. static    OSErr getDType (tnode_t *, StringPtr);
  31. static    OSErr openDistFile (struct iob *);
  32. static    OSErr readDLine (struct iob *, StringPtr);
  33. static    void skipSpaces (StringPtr, int *);
  34.  
  35.  
  36. /*
  37.  *=========================================================================
  38.  * freeDist (node) - free dist_node tree
  39.  * entry:    node = ptr to root of tree
  40.  *=========================================================================
  41.  */
  42. void
  43. freeDist (node)
  44.     dnode_t        *node;
  45. {
  46.     dnode_t        *parent, *child, *prev, *next;
  47.     tnode_t        *tp, *pp, *np;
  48.  
  49.     if (node == nil)
  50.         return;
  51.     /*
  52.      * First, unlink this node from any sibling chain
  53.      * (If our parent's child pointer is nil, skip this.)
  54.      */
  55.     if ((parent = node->parentp))
  56.     {
  57.         if ((prev = parent->childp))
  58.         {
  59.             if (prev == node)
  60.                 /* node is first child */
  61.                 parent->childp = node->sibp;
  62.             else
  63.                 /* scan sib list for node */
  64.                 for (next = prev->sibp; next; prev = next, next = next->sibp)
  65.                     if (next == node)
  66.                     {
  67.                         prev->sibp = node->sibp;
  68.                         break;
  69.                     }
  70.             node->sibp = nil;
  71.         }
  72.     }
  73.     /*
  74.      * Next, recursively free any children
  75.      */
  76.     for (next = node->childp, node->childp = nil; next; )
  77.     {
  78.         prev = next;
  79.         next = next->sibp;
  80.         freeDist (prev);
  81.     }
  82.     /*
  83.      * Free any type_nodes back to parent's
  84.      */
  85.     pp = parent ? parent->tlistp : nil;
  86.     for (tp = node->tlistp; tp && tp != pp; tp = np)
  87.     {
  88.         np = tp->morep;
  89.         DisposPtr ((Ptr) tp);
  90.     }
  91.     /*
  92.      * Finally, free selves
  93.      */
  94.     if (node->altname)
  95.         DisposPtr ((Ptr) node->altname);
  96.     DisposPtr ((Ptr) node);
  97. }
  98.  
  99.  
  100.  
  101. /*
  102.  *=========================================================================
  103.  * parseDistFile () - build a dist_node tree from the control file
  104.  * entry:    This is a dispatcher routine.
  105.  *            The calling argument pointer is ignored.
  106.  * returns:    nil on failure, reason in ClueID, etc
  107.  *            ptr to dist_node tree if file read correctly.
  108.  *
  109.  * There are five formats for lines in the control file:
  110.  * - Comments, which begin with #
  111.  * - Folder starts, which begin with > and look like
  112.  *        > Foldername :Folderactions [:Alternate name]
  113.  * - Folder ends, which begin with < and look like
  114.  *        < Foldername :DefaultActionsForFolder
  115.  * - Files, which begin with | and look like
  116.  *        | Filename :Fileactions [:Alternate name]
  117.  * - Type/creator specifications, which begin with * and look like
  118.  *        * Type :Actions
  119.  *        * (Creator) :Actions
  120.  *     or    * Type(Creator) :Actions
  121.  *     where Type is a four character file type and Creator is a four
  122.  *     character file creator signature.
  123.  *     or    * alias    :Actions
  124.  *     where alias is a symbolic name for "alis(MACS)"
  125.  *     or * icons    :Actions
  126.  *     where icons is a symbolic name for "icon(MACS)"
  127.  *=========================================================================
  128.  */
  129.  
  130. DISPATCHED (parseDistFile)
  131. {
  132.     struct    lm                        /* local memory */
  133.     {
  134.         frame_t            f;
  135.         struct iob *    iob;
  136.         int                ecnt;        /* error count */
  137.         int                lcnt;        /* control file line counter */
  138.         dnode_t *        head;        /* ptr to base of tree */
  139.         dnode_t *        parent;        /* parent node */
  140.         dnode_t *        prev;        /* previous node in sibling chain */
  141.         dnode_t *        next;        /* next node in sibling chain */
  142.     };
  143.     typedef struct lm    lm_t;
  144. register lm_t            *m;            /* ptr to local memory */
  145.     int                    cmp;        /* 0 if duplicate name */
  146.     OSErr                error;        /* serious error number */
  147.     int                    idx;        /* index into lineBuf */
  148. register dnode_t *        node;        /* working node */
  149.     int                    len;        /* length of current line */
  150.     Ptr                    p;            /* temp pointer */
  151.     Ptr                    paramv[2];    /* args/return values */
  152.     int                    sel;        /* type of control file entry */
  153.     StringPtr            str;        /* string temp */
  154.     tnode_t *            tp;            /* current type_node */
  155.     actions_t            actions;    /* action list for current node */
  156.     Str255                lineBuf;    /* buffer for line from control file */
  157.     Str255                nBuf;        /* current component name */
  158.     Str255                tBuf;        /* temp buffer */
  159.  
  160.     error = 0;
  161.     m = *(lm_t **)fh;
  162.     switch (request)
  163.     {
  164.     case R_INIT:
  165.         /*
  166.          * Initial call: just see if we can get the memory we will need
  167.          * and open the control file.
  168.          */
  169.         if (error = resizeFrame (fh, sizeof (lm_t)))
  170.             break;
  171.         p = NewPtr (sizeof (struct iob) + 512 - 1);
  172.         HLock ((Handle)fh);
  173.         m = *(lm_t **)fh;
  174.         m->iob = (struct iob *) p;
  175.         if (p == nil)
  176.         {
  177.             Clue1 = "\pNewPtr";
  178.             error = MemError();
  179.             break;
  180.         }
  181.         m->iob->size = 512;
  182.         m->iob->cnt = m->iob->idx = 0;
  183.         m->iob->refNum = 0;
  184.         error = openDistFile (m->iob);
  185.         if (error)
  186.             break;
  187.         if (alias[0] == 0)
  188.         {
  189.             Clue1 = "\pGetIndString";
  190.             GetIndString(tBuf, MISC_STR, ALIAS_WORD);
  191.             if (tBuf[0] && tBuf[0] < sizeof (alias))
  192.                 COPYPS(tBuf, alias);
  193.             else
  194.                 goto cantgetres;
  195.             GetIndString(tBuf, MISC_STR, ALIAS_INFO);
  196.             if (tBuf[0] == sizeof(AliasType) + sizeof(AliasCreator))
  197.             {
  198.                 BlockMove(tBuf+1, (Ptr)&AliasType, sizeof(AliasType));
  199.                 BlockMove(tBuf+1+sizeof(AliasType), (Ptr)&AliasCreator, sizeof(AliasCreator));
  200.             }
  201.             else
  202.                 goto cantgetres;
  203.             GetIndString(tBuf, MISC_STR, ICON_WORD);
  204.             if (tBuf[0] && tBuf[0] < sizeof (icons))
  205.                 COPYPS(tBuf, icons);
  206.             else
  207.                 goto cantgetres;
  208.             GetIndString(tBuf, MISC_STR, ICON_INFO);
  209.             if (tBuf[0] == sizeof(IconType) + sizeof(IconCreator))
  210.             {
  211.                 BlockMove(tBuf+1, (Ptr)&IconType, sizeof(IconType));
  212.                 BlockMove(tBuf+1+sizeof(IconType), (Ptr)&IconCreator, sizeof(IconCreator));
  213.             }
  214.             else
  215.                 goto cantgetres;
  216.             GetIndString(tBuf, MISC_STR, ICON_FNAME);
  217.             if (tBuf[0] && tBuf[0] < sizeof (IconFName))
  218.                 COPYPS(tBuf, IconFName);
  219.             else
  220.             {
  221. cantgetres:
  222.                 error = ResError();
  223.                 if (error == 0)
  224.                     error = bdNamErr;    /* not really */
  225.                 break;
  226.             }
  227.         }
  228.  
  229.         m->f.state = 1;
  230.         HUnlock ((Handle)fh);
  231.         return R_CONT;
  232.  
  233.     case R_CONT:
  234.         /*
  235.          * We have only one "continue" state, and in that state we
  236.          * process one line from the control file per call
  237.          */
  238.         if (m->f.state != 1)
  239.         {
  240.             Clue0 = "\pparseDistFile";
  241.             NumToString ((long)m->f.state, Mbuf);
  242.             panic (true, E_STATE, NullStr, Mbuf, nil);
  243.             return R_QUIT;
  244.         }
  245.  
  246.         error = readDLine (m->iob, lineBuf);
  247.         if (error)
  248.             break;
  249.         m->lcnt++;
  250.         if (Flags & PF_ECHODIST)
  251.         {
  252.             DisplayInt (m->lcnt);
  253.             DisplayString (lineBuf);
  254.             DisplayLn ();
  255.         }
  256.         len = lineBuf[0];
  257.         idx = 1;
  258.         skipSpaces (lineBuf, &idx);
  259.         /*
  260.          * skip empty lines and lines beginning with #
  261.          */
  262.         if (idx > len || lineBuf[idx] == '#')
  263.             break;
  264.         /*
  265.          * see which type of line we have
  266.          */
  267.         sel = lineBuf[idx++];
  268.         if (sel != '<' && sel != '|' && sel != '>' && sel != '*')
  269.         {
  270.             error = E_PREFIX;
  271. synerr:
  272.             m->ecnt++;
  273.             GetIndString (tBuf, ERR_STR, error);
  274.             DisplayString (tBuf);
  275.             DisplayInt (m->lcnt);
  276.             DISPLAY ("\p : ");
  277.             DisplayString (lineBuf);
  278.             DISPLAY ("\p\r");
  279.             error = 0;
  280.             break;
  281.         }
  282.         /*
  283.          * extract the file/folder name or type/creator
  284.          */
  285.         if (getDField (lineBuf, &idx, ':', nBuf))
  286.         {
  287.             error = E_NOFNAME;
  288.             goto synerr;
  289.         }
  290.         if (sel != '*' && strchr ((char *)nBuf+1, ':'))
  291.         {
  292.             error = E_BADNAME;
  293.             goto synerr;
  294.         }
  295.         /*
  296.          * extract and interpret the actions list
  297.          */
  298.         if (getDField (lineBuf, &idx, ' ', tBuf))
  299.         {
  300.             error = E_NOACTION;
  301.             goto synerr;
  302.         }
  303.         if (getDActions (tBuf, &actions))
  304.         {
  305.             error = E_BADACTION;
  306.             goto synerr;
  307.         }
  308.         /*
  309.          * extract the server alternate name field, if present
  310.          */
  311.         if (getDField (lineBuf, &idx, 0x100, tBuf) == 0)
  312.         {
  313.             if (tBuf[0] < 2 || tBuf[1] != '=')
  314.             {
  315.                 error = E_ALTNAME;
  316.                 goto synerr;
  317.             }
  318.         }
  319.         /*
  320.          * Now that we've parsed the line into its pieces, use the
  321.          * pieces to fill in its dist_node
  322.          */
  323.         switch (sel)
  324.         {
  325.         case '<':
  326.             /*
  327.              * end of folder contents
  328.              * verify that there is a folder for us to match,
  329.              * then copy actions to folder default entry
  330.              * and unnest a level
  331.              */
  332.             if (m->parent == nil)
  333.             {
  334.                 error = E_LAST;
  335.                 break;
  336.             }
  337.             if ((node = m->parent->childp) == nil
  338.             ||  node->d_type != D_FOLDERDEF
  339.             ||  node->name[0] != 0
  340.             )
  341.             {
  342.                 error = E_ENDFERR;
  343.                 goto emexit;
  344.             }
  345.             if (!EqualString(m->parent->name, nBuf, false, true))
  346.             {
  347.                 error = E_DISTBAD;
  348.                 goto emexit;
  349.             }
  350.             node->actions = actions;
  351.             node = node->parentp;
  352.             m->parent = node->parentp;
  353.             m->prev = m->next = node;
  354.             break;
  355.  
  356.         case '|':
  357.             if (m->head == nil)
  358.             {
  359.                 error = E_FIRST;
  360.                 break;
  361.             }
  362.             /* fall into ... */
  363.         case '>':
  364.             /*
  365.              * for files and folders, create a new node, fill it in,
  366.              * and link it in alphabetically
  367.              */
  368.             node = (dnode_t *) NewPtr (sizeof (dnode_t));
  369.             if (node == nil)
  370.             {
  371.                 error = MemError();
  372.                 break;
  373.             }
  374.             ZEROAT(node);
  375.             node->parentp = m->parent;
  376.             node->d_type = sel == '|' ? D_FILE : D_FOLDER;
  377.             node->actions = actions;
  378.             COPYPS (nBuf, node->name);
  379.             if (m->head == nil)
  380.             {
  381.                 m->head = node;
  382.                 m->prev = m->next = node;
  383.             }
  384.             else
  385.             {
  386.                 if (m->parent == nil || m->prev == nil)
  387.                 {
  388.                     DisposPtr ((Ptr) node);
  389.                     error = E_DISTBAD;
  390. emexit:
  391.                     /*
  392.                      * Here for error where showing the bad control file line
  393.                      * makes sense
  394.                      */
  395.                     COPYPS (lineBuf, Mbuf);
  396.                     Clue1 = Mbuf;
  397.                     break;
  398.                 }
  399.                 /*
  400.                  * insert alphabetically in sibling chain
  401.                  */
  402.                 if (RelString (nBuf, m->prev->name, false, true) < 0)
  403.                     m->prev = m->next = m->parent->childp;
  404.                 for (cmp = -1; m->next; m->prev = m->next, m->next = m->next->sibp)
  405.                     if ((cmp = RelString (nBuf, m->next->name, false, true)) <= 0)
  406.                         break;
  407.                 if (cmp == 0)
  408.                 {
  409.                     error = E_DUPENAME;
  410.                     DisposePtr ((Ptr) node);
  411.                     goto synerr;
  412.                 }
  413.                 node->sibp = m->next;
  414.                 m->prev->sibp = node;
  415.                 m->prev = node;
  416.             }
  417.             /*
  418.              * If there is an alternate name, copy it to alloc'ed space
  419.              * (except for the leading = )
  420.              */
  421.             if ((len = tBuf[0]))
  422.             {
  423.                 if ((node->altname = (StringPtr) NewPtr (len)) == nil)
  424.                 {
  425.                     if (!(error = MemError()))
  426.                         error = memFullErr;
  427.                     break;
  428.                 }
  429.                 BlockMove (tBuf+1, node->altname, (long) len);
  430.                 node->altname[0] = len - 1;
  431.             }
  432.             /*
  433.              * If a file, done.
  434.              */
  435.             if (sel == '|')
  436.                 break;
  437.             /*
  438.              * Propagate our parent's type_node list
  439.              */
  440.             if (node->parentp)
  441.                 node->tlistp = node->parentp->tlistp;
  442.             /*
  443.              * Allocate a dummy child which will hold the folder defaults
  444.              */
  445.             m->next = (dnode_t *) NewPtr (sizeof (dnode_t));
  446.             if (m->next == nil)
  447.             {
  448.                 if (!(error = MemError()))
  449.                     error = memFullErr;
  450.                 break;
  451.             }
  452.             ZEROAT(m->next);
  453.             m->next->parentp = node;
  454.             m->next->d_type = D_FOLDERDEF;
  455.             node->childp = m->next;
  456.             m->parent = node;
  457.             m->prev = m->next;
  458.             break;
  459.  
  460.         case '*':
  461.             /*
  462.              * File type/creator selection.
  463.              * Allocate a type_list node and link it in to the current
  464.              * folder dist_node.
  465.              */
  466.             node = m->parent;
  467.             if (node == nil)
  468.             {
  469.                 error = E_FIRST;
  470.                 break;
  471.             }
  472.             tp = (tnode_t *) NewPtr (sizeof (tnode_t));
  473.             if (tp == nil)
  474.             {
  475.                 error = memFullErr;
  476.                 break;
  477.             }
  478.             ZEROAT (tp);
  479.             error = getDType (tp, nBuf);    /* fill in type/creator */
  480.             if (error)
  481.             {
  482.                 DisposPtr ((Ptr) tp);
  483.                 break;
  484.             }
  485.             tp->actions = actions;            /* fill in actions */
  486.             tp->morep = node->tlistp;
  487.             node->tlistp = tp;
  488.             break;
  489.         }
  490.         break;
  491.  
  492.     case R_BACKOUT:
  493.     case R_QUIT:
  494.         error = E_QUIT;                /* magic error number */
  495.         break;
  496.  
  497.     default:
  498.         error = E_REQUEST;            /* cannot happen */
  499.  
  500.     }
  501.     /*
  502.      * If this call had a serious error or if the end of the file was
  503.      * reached and there were previous minor (syntax) errors, clean up
  504.      * and return an error to the caller.
  505.      * Otherwise, pop back to caller, returning the head of the tree we built.
  506.      * In any case, close the file and return the iob resources.
  507.      */
  508.     if (error == 0)
  509.     {
  510.         /*
  511.          * if error is not set, we are not done.
  512.          */
  513.         return R_CONT;
  514.     }
  515.     if (GetHandleSize ((Handle)fh) < sizeof (lm_t))
  516.         return (popCall (E_QUIT, nil));
  517.     /*
  518.      * EOF error is not a real error.  It is how we know we are done.
  519.      */
  520.     if (error == eofErr)
  521.     {
  522.         error = 0;
  523.         /*
  524.          * Check that start and end folders balanced out
  525.          */
  526.         if (m->parent)
  527.             error = E_LAST;
  528.     }
  529.     if (error == 0 && m->ecnt)
  530.         error = E_DISTL;
  531.     if (m->iob)
  532.     {
  533.         file_info_t *    fi;
  534.  
  535.         fi = &File_list[FL_DIST];
  536.         if (m->iob->refNum)
  537.         {
  538.             (void) FSClose (m->iob->refNum);
  539.             if (m->iob->refNum == fi->f_ref)
  540.                 fi->f_ref = 0;
  541.         }
  542.         DisposPtr ((Ptr) m->iob);
  543.         m->iob = 0;
  544.     }
  545.     if (error)
  546.     {
  547.         ClueID = error;
  548.         Clue0 = "\pparseDistFile";
  549.         freeDist (m->head);
  550.         m->head = 0;
  551.     }
  552.     paramv[0] = (Ptr) m->head;
  553.     return (popCall (request==R_INIT ? R_CONT : request, paramv));
  554. }
  555.  
  556.  
  557. /*
  558.  *=========================================================================
  559.  * getDActions (str, ap) - decode action list
  560.  * entry:    str = string with action list text
  561.  *            ap = ptr to action structure to set from action list
  562.  * returns:    0 if no error, else non-zero
  563.  *=========================================================================
  564.  */
  565. static
  566. OSErr
  567. getDActions (str, ap)
  568. register StringPtr        str;
  569. register actions_t *    ap;
  570. {
  571. register int            c;
  572. register int            i;
  573. register int            len;
  574.     int                    opt;
  575.  
  576.     memset ((char *) ap, A_DEFAULT, sizeof (*ap));
  577.     for (i = 0, len = str[0]; i+1 < len; )
  578.     {
  579.         c = str[++i];                /* letter for which condition */
  580.         if (c >= 'a' && c <= 'z')
  581.             c = c - 'a' + 'A';
  582.         opt = c;
  583.         c = str[++i];                /* letter for which action */
  584.         if (c >= 'A' && c <= 'Z')
  585.             c = c - 'A' + 'a';
  586.         switch (c)
  587.         {
  588.         case '.':    c = A_DEFAULT;    break;
  589.         case '-':    c = A_PASS;        break;
  590.         case 'i':    c = A_IGNORE;    break;
  591.         case 'j':    if (opt == 'H' || opt == 'L' || opt == 'B' || opt == 'R')
  592.                         c = A_IGNORE;
  593.                     else
  594.                         c = A_JUNK;
  595.                     break;
  596.         case 'd':    c = A_DISCARD;    break;
  597.         case 'u':    c = A_UPDATE;    break;
  598.         case 's':    if (opt == 'H' || opt == 'L' || opt == 'B' || opt == 'R')
  599.                     {
  600.                     c = A_SET;        break;
  601.                     }
  602.                     /* else fall into */
  603.         default:    return E_BADACTION;
  604.         }
  605.         switch (opt)
  606.         {
  607.         case 'C':    ap->ifclient = c;    break;
  608.         case 'S':    ap->ifserver = c;    break;
  609.         case 'V':    ap->ifcreate = c;    break;
  610.         case 'N':    ap->ifnewer = c;    break;
  611.         case 'O':    ap->ifolder = c;    break;
  612.         case 'Z':    ap->ifsize = c;        break;
  613.         case 'E':    ap->otherwise = c;    break;
  614.         case 'W':    ap->copywindow = c;    break;
  615.         case 'H':    ap->invisible = c;    break;
  616.         case 'L':    ap->locked = c;        break;
  617.         case 'B':    ap->backup = c;        break;
  618.         case 'R':    ap->reboot = c;        break;
  619.         case 'A':    ap->ifclient = c;
  620.                     ap->ifserver = c;
  621.                     ap->ifcreate = c;
  622.                     ap->ifnewer = c;
  623.                     ap->ifolder = c;
  624.                     ap->ifsize = c;
  625.                     ap->otherwise = c;
  626.                     ap->copywindow = c;
  627.                     ap->invisible = c;
  628.                     ap->locked = c;
  629.                     break;
  630.         default:    return E_BADACTION;
  631.         }
  632.     }
  633.     return 0;
  634. }
  635.  
  636.  
  637.  
  638. /*
  639.  *=========================================================================
  640.  * getDField (src, idx, term, dst) - extract field from line
  641.  *                where a field is delimited by term character or end of line
  642.  * entry:    src = ptr to line
  643.  *            idx = ptr to current index into src line
  644.  *            term = character to use to terminate field
  645.  *                special values:
  646.  *                    ' ' -> terminate on whitespace
  647.  *                    ':' -> terminate on ':' and also strip trailing whitespace
  648.  *            dst = ptr to string to receive field
  649.  * returns:    0 if field found, idx updated
  650.  *            <> 0 if no field remaining in line
  651.  *=========================================================================
  652.  */
  653. static
  654. int
  655. getDField (
  656. register    StringPtr    src,
  657.             int    *        idx,
  658.             int            term,
  659. register    StringPtr    dst)
  660. {
  661.     register    int        len;
  662.     register    int        i, j;
  663.     register    int        c;
  664.                 int        k;            /* tracks last non-whitespace */
  665.                 int        l, n;        /* for \ddd conversions */
  666.  
  667.     skipSpaces (src, idx);            /* skip leading spaces */
  668.     len = src[0];
  669.     i = *idx;
  670.     j = 0;
  671.     k = j;
  672.     dst[j] = 0;
  673.     if (i > len)
  674.         return -1;                    /* no field data present */
  675.     while (i <= len)
  676.     {
  677.         c = src[i++];
  678.         if (c == '\\' && i <= len)    /* allow \ to quote chars */
  679.         {
  680.             c = src[i++];
  681.             if (c >= '0' && c <= '9')    /* if \ddd character */
  682.             {
  683.                 l = i + 2; if (l > len) l = len;
  684.                 n = c - '0';
  685.                 while (i <= l && (c = src[i]) >= '0' && c <= '9')
  686.                 {
  687.                     n = n * 10 + c - '0';
  688.                     i++;
  689.                 }
  690.                 c = n;
  691.             }
  692.             dst[++j] = c;
  693.             k = j;
  694.         }
  695.         else
  696.         {
  697.             if (c == term)
  698.                 break;
  699.             if (term == ' ' && c == '\t')
  700.                 break;
  701.             dst[++j] = c;
  702.             if (c != ' ' && c != '\t')
  703.                 k = j;
  704.         }
  705.     }
  706.     *idx = i;
  707.     if (term == ':')
  708.         j = k;
  709.     dst[j+1] = 0;
  710.     dst[0] = j;
  711.     return 0;
  712. }
  713.  
  714.  
  715.  
  716. /*
  717.  *=========================================================================
  718.  * getDType (tp, sp) - Parse TYPE and CREATOR string
  719.  * entry:        tp = ptr to type_node to fill in
  720.  *                sp = ptr to string with type and creator
  721.  * returns:        0 if no error, else error number
  722.  *=========================================================================
  723.  */
  724.  
  725. OSErr
  726. getDType (tp, sp)
  727. register tnode_t *    tp;
  728. register StringPtr    sp;
  729. {
  730. register    int        len;            /* chars in sp */
  731.             OSErr    error;
  732.  
  733. #define    LT    sizeof(tp->ftype)        /* length of a file type */
  734. #define    LC    sizeof(tp->fcreator)    /* length of a file creator */
  735.  
  736.  
  737.     error = E_BADTYPE;                /* assume failure */
  738.     len = sp[0];                    /* string length */
  739.     /*
  740.      * Check for special entries which indicate Finder alias file
  741.      * or icon file
  742.      */
  743.     if (len == alias[0] && EqualString(sp, alias, false, true))
  744.     {
  745.         tp->ftype = AliasType;
  746.         tp->fcreator = AliasCreator;
  747.         error = 0;
  748.     }
  749.     else
  750.     if (len == icons[0] && EqualString(sp, icons, false, true))
  751.     {
  752.         tp->ftype = IconType;
  753.         tp->fcreator = IconCreator;
  754.         error = 0;
  755.     }
  756.     else
  757.     {
  758.         switch (len)
  759.         {
  760.         case LT:                    /* just TYPE */
  761.             BlockMove (sp+1, (Ptr)&tp->ftype, LT);
  762.             error = 0;
  763.             break;
  764.  
  765.         case 1+LC+1:                /* just (CREATOR) */
  766.             if (sp[1] == '(' && sp[len] == ')')
  767.             {
  768.                 BlockMove (sp+2, (Ptr)&tp->fcreator, LC);
  769.                 error = 0;
  770.             }
  771.             break;
  772.  
  773.         case LT+1+LC+1:                /* TYPE(CREATOR) */
  774.             if (sp[LT+1] == '(' && sp[len] == ')')
  775.             {
  776.                 BlockMove (sp+1, (Ptr)&tp->ftype, LT);
  777.                 BlockMove (sp+1+LT+1, (Ptr)&tp->fcreator, LC);
  778.                 error = 0;
  779.             }
  780.             break;
  781.         }
  782.     }
  783.     return error;
  784. }
  785.  
  786.  
  787.  
  788. /*
  789.  *=========================================================================
  790.  * openDistFile (iob) - locate and open the control file
  791.  * entry:    iob = pointer to iob structure
  792.  *            File_list9 global names the control file
  793.  * exit:    returns 0 if file opened,
  794.  *            else error number
  795.  *=========================================================================
  796.  */
  797. static
  798. OSErr
  799. openDistFile (iob)
  800. struct iob *    iob;
  801. {
  802.     OSErr        error;
  803.     file_info_t *    fi;
  804.     Integer            ref;
  805.     StringHandle    sh;
  806.     HParamBlockRec    pb;
  807.  
  808.     iob->cnt = 0;
  809.     iob->idx = 0;
  810.     fi = &File_list[FL_DIST];
  811.     if (ref = fi->f_ref)
  812.     {
  813.         iob->refNum = ref;
  814.         return 0;
  815.     }
  816.     sh = fi->f_path;
  817.     HLock ((Handle) sh);
  818.     ZERO (pb);
  819.     pb.fileParam.ioNamePtr = *sh;
  820.     pb.fileParam.ioVRefNum = fi->f_vol;
  821.     pb.ioParam.ioPermssn = fsRdPerm;
  822.     error = PBHOpen (&pb, false);
  823.     if (error == 0)
  824.         ref = pb.ioParam.ioRefNum;
  825.     else
  826.     {
  827.         Clue0 = "\popenDistFile";
  828.         Clue1 = "\pFSOpen";
  829.         Clue2 = *sh;
  830.         ref = 0;
  831.     }
  832.     fi->f_ref = iob->refNum = ref;
  833.     return error;
  834. }
  835.  
  836.  
  837. /*
  838.  *=========================================================================
  839.  * readDLine (iob, str) - read line from file into string
  840.  * entry    iob = ptr to I/O control structure
  841.  *            str = string to receive line
  842.  *=========================================================================
  843.  */
  844. static
  845. OSErr
  846. readDLine (iob, str)
  847. register struct iob *    iob;
  848. register StringPtr        str;
  849. {
  850. register int        c;                /* current character */
  851.     Longint            count;            /* bytes read */
  852.     OSErr            error;
  853. register int        len;            /* valid bytes in I/O buffer */
  854. register int        i, j;            /* indexes into buffer, str */
  855.  
  856.     error = 0;
  857.     len = iob->cnt;
  858.     i = iob->idx;
  859.     j = 0;
  860.     c = 0;                            /* set not in quote character */
  861.     for (;;)
  862.     {
  863.         if (i >= len)
  864.         {
  865.             /*
  866.              * if buffer exhausted, read some more
  867.              */
  868.             count = iob->size;
  869.             error = FSRead (iob->refNum, &count, iob->buf);
  870.             iob->cnt = len = count;
  871.             i = 0;
  872.             if (error == eofErr)
  873.                 error = 0;
  874.             if (error)
  875.             {
  876.                 ClueID = error;
  877.                 Clue0 = "\preadDLine";
  878.                 Clue1 = "\pFSRead";
  879.                 break;
  880.             }
  881.             if (len <= 0)
  882.             {
  883.                 if (j == 0)
  884.                     error = eofErr;    /* if nothing left, return eof */
  885.                 break;                /* if didn't get anything, quit */
  886.             }
  887.             continue;
  888.         }
  889.         if (c == -1)
  890.             str[++j] = c = iob->buf[i++];    /* copy quoted char exactly */
  891.         else
  892.         {
  893.             c = iob->buf[i++];
  894.             if (c == '\n' || c == '\r')
  895.                 break;                    /* exit on end of line */
  896.             str[++j] = c;
  897.             if (c == '\\')
  898.                 c = -1;                    /* flag next char quoted */
  899.         }
  900.         if (j >= 255)
  901.             break;
  902.     }
  903.     iob->idx = i;
  904.     str[0] = j;
  905.     if (j < 255)
  906.         str[j+1] = 0;
  907.     return error;
  908. }
  909.  
  910.  
  911.  
  912. /*
  913.  *=========================================================================
  914.  * skipSpaces (src, idx) - skip leading spaces in string
  915.  * entry:    src = ptr to string
  916.  *            idx = ptr to current index in string
  917.  * exit        idx advanced past any leading whitespace in string
  918.  *=========================================================================
  919.  */
  920. static
  921. void
  922. skipSpaces (src, idx)
  923. register StringPtr    src;
  924. register int *        idx;
  925. {
  926. register int        len;
  927. register int        c;
  928. register int        i;
  929.  
  930.     len = src[0];
  931.     i = *idx;
  932.     while (i <= len)
  933.     {
  934.         c = src[i];
  935.         if (c != ' ' && c != '\t')
  936.             break;
  937.         ++i;
  938.     }
  939.     *idx = i;
  940. }